

#include "mainfunc.h"
// #include <SimpleMap.h>
#include <ArduinoJson.h>
#include "utils.h"
#include "global.h"
#include "Http.h"
#include "httpfunc.h"
#include "NTPTime.h"
#include "BizUtils.h"
#include "ota.h"
#include "ActionCtrl.h"
#include "mainHumi.h"

#include "bucket_plant_water/bucket_plant_water.h"
#include "CondNotice.h"
#include "timer.h"
#include "SensorData.h"
 

// SimpleMap<String,TimerCBClass> timerCallbackMap = new SimpleMap<String,TimerCBClass>();

Ticker flipper; // 实例化定时器对象

WAKEUP_MODE wakeUpMode;

static int count = 0;
bool sendEnalbe = false;
bool issetup = false;
#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */

bool isStartTimerWakeup = false;
bool isStartGpioWakeup = false;

int gpioWakeupDelayTime = 0;
int gpioWakeupCount = 0;

long wakeupDelayCount = 0;
long wakeupDelayTime = 0;

long sleepDelayTime = 0;

int UploadFrequnce = 60 * 10; // 60s 上传频率，可设置
bool longClick = false;
const int wdtTimeout = 30000; // time in ms to trigger the watchdog
hw_timer_t *timer = NULL;

hw_timer_t *timerButton = NULL;

// extern const int MAX_CALLBACK_COUNT;
#define MAX_CALLBACK_COUNT 20
extern FuncCallBackStruct *timercallbacks[MAX_CALLBACK_COUNT];
extern FuncCallBackStruct1 *timercallbacks1[MAX_CALLBACK_COUNT];

static const String LONG_CLICK_LISTENER = "LONG_CLICK_LISTENER";
int BUTTON_PIN = 0;
extern bool longClick;
long longClickPressTime = 0;
long longClickReleaseTime = 0;
static bool isAppStartValue = false;
bool isHanddleClick = false;
// extern B gloablInterValAction[10];
// extern B gloablInterValAction[10];

extern  B gloablInterValAction[10];
//extern RTC_DATA_ATTR B gloablWeekAction[7][10];

void ARDUINO_ISR_ATTR resetModule()
{
  ets_printf("reboot watchdog \n");
  esp_restart();
}

volatile long j = 0;
void timerCallback1()
{
  // printStr("1");
  j++;
}
void timerCallback()
{

 // checkLowPower();测试暂时注释

  for (int i = 0; i < MAX_CALLBACK_COUNT; i++)
  {
    FuncCallBackStruct *call = timercallbacks[i];
    if (call == nullptr)
    {
      continue;
    };
    call->plusCount();
    if (call->callback != nullptr)
    {
      call->callback(String(call->count));
    }

    // void*参数
    FuncCallBackStruct1 *call1 = timercallbacks1[i];
    if (call1 == nullptr)
    {
      continue;
    };
    call1->plusCount();
    if (call1->callback != nullptr)
    {
      call1->callback(call1);
    }
  }
}

// 如果5秒之后没有监听到长按事件则启动应用程序
void TimerCB(String s)
{
  if (s == nullptr)
  {
    return;
  }
  int i = s.toInt();
  Serial.println(i);
  if (i == 5)
  {
    if (!longClick)
    {
      isAppStartValue = true;
    }
    removeGlobalTimerCallBack(LONG_CLICK_LISTENER);
  }
}

void sleepDelayCallBack(String s)
{
  long t = s.toInt();
  if (t >= sleepDelayTime)
  {
    removeGlobalTimerCallBack("sleep");

    startSleep(0);
  }
}

void activeError(String error)
{
  Serial.println(error);
}

void onActiveError(String error)
{
  Serial.print("激活错误:");
  Serial.println(error);
  String str("device-active-error:");
  str.concat(error);
  sendNotify(str);
}

void delayCallBack1(String s)
{
  setEnv("pro");
}

void onActivePostBack(String msg)
{
  Serial.println("返回:" + msg);
  JsonDocument doc;
  DeserializationError error = deserializeJson(doc, msg);

  if (error)
  {
    Serial.print(F("deserializeJson() failed: "));
    Serial.println(error.f_str());
    return;
  }
  int code = doc["code"];
  String topic = doc["topic"];
  if (code == 200)
  {
    if (topic.equals("active"))
    {
      String token = doc["data"];
      if (token != nullptr)
      {
        // 激活成功

        putPreferenceString("token", token);
        setActive(true);
        sendNotify("device-active-ok");

        // lightGreenLed();
        long time = 60 * 2;
        // setWakeupDelayTime(time);
        // startTimerSleepWakeup(); // 延迟2分钟

        excuteDelay(40, delayCallBack1);
      }
    }
  }
  else
  {
    const char *msg = doc["msg"];
    String str("device-active-error:");
    str.concat(msg);
    sendNotify(str);
  }
}

void startSleep(long second)
{

  if (second == 0)
  {

    WAKEUP_MODE wakeup = getSleepMode();
    switch (wakeup)
    {
    case GPIO_MODE:
    {
      Serial.println("sleep now,you can press button to wake up...");
      Serial.println("GPIO_MODE");
      break;
    }

    case TIMER_MODE:
    {
      long timerWakeWake = getTimerWakeup();
      String str = "sleep now,after " + String(timerWakeWake) + " will wake up!";
      Serial.println(str);
      Serial.println("TIMER_MODE");
      break;
    }

    case GPIO_TIMER_MODE:
    {
      long timerWakeWake1 = getTimerWakeup();
      // timerWakeWake1=500;//测试
      printStr("睡眠时长", timerWakeWake1);
      String str1 = "sleep now,after " + String(timerWakeWake1) + " will wake up! and you can press button to wakeup!";
      Serial.println(str1);
      Serial.println("GPIO_TIMER_MODE");
      break;
    }

    default:
      break;
    }
    esp_deep_sleep_start();
  }
  else
  {
    sleepDelayTime = second;
    removeGlobalTimerCallBack("sleep");
    addGlobalTimerCallBack("sleep", sleepDelayCallBack);
  }
}

bool isReadySleep()
{
  if (getGlobalFuncCallBack("sleep") != nullptr)
  {
    return true;
  }
  return false;
}

void cancelSleep()
{
  removeGlobalTimerCallBack("sleep");
}

void setSleepMode(WAKEUP_MODE mode)
{
  wakeUpMode = mode;
  if (mode == GPIO_MODE)
  {
    gpio_set_direction(GPIO_NUM_0, GPIO_MODE_INPUT);
    esp_deep_sleep_enable_gpio_wakeup(BIT(0), ESP_GPIO_WAKEUP_GPIO_LOW);
    esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER);
  }
  else if (mode == TIMER_MODE)
  {
    esp_sleep_enable_timer_wakeup(getTimerWakeup() * uS_TO_S_FACTOR);
  }
  else
  {
    gpio_set_direction(GPIO_NUM_0, GPIO_MODE_INPUT);
    esp_deep_sleep_enable_gpio_wakeup(BIT(0), ESP_GPIO_WAKEUP_GPIO_LOW);
    esp_sleep_enable_timer_wakeup(getTimerWakeup() * uS_TO_S_FACTOR);
  }
}

WAKEUP_MODE getSleepMode()
{
  return wakeUpMode;
}

void attachGlobalTimer()
{
  flipper.attach(1, timerCallback); // 每隔1秒执行一次回调函数
}

void dettachGlobalTimer()
{
  flipper.detach();
}

void setupWatchDog()
{
  timer = timerBegin(0, 60, true);                  // timer 0, div 80
  timerAttachInterrupt(timer, &resetModule, true);  // attach callback
  timerAlarmWrite(timer, wdtTimeout * 1000, false); // set time in us
  timerAlarmEnable(timer);
}

bool IRAM_ATTR TimerHandler1(void *timerNo)
{

  j++;

  return true;
}

void attachButtonCheckTimer()
{
}
void dettachButtonCheckTimer()
{
}
void feedWatchDog()
{
  timerWrite(timer, 0); // reset timer (feed watchdog)
}
OneButton btn = OneButton(
    BUTTON_PIN, // Input pin for the button
    true,       // Button is active LOW
    true        // Enable internal pull-up resistor
);

void loopBtn()
{
  btn.tick();
}

void delayConfigWifi(String s)
{
  stopAdvertising();
}

void handleLongClickStart()
{

  // if (isAdvertising())
  // {
  //   ESP.restart();
  //   return;
  // }

  longClickPressTime = millis();
  beepTimes(1);
  removeGlobalTimerCallBack(LONG_CLICK_LISTENER);
  Serial.println("handleLongClickStart...");
  setupBle(); // 初始化蓝牙设备
  startAdvertising();
  setSendData(false);
  blink("r", 60 * 10);
  removeGlobalTimerCallBack("connectWiFi");   // 是否有必要加这个？
  removeGlobalTimerCallBack("delayStartApp"); // 这个必须加
  if (getAppMode() == 2)
  { // 如果是节能模式
    if (isActive())
    {
      setSleepMode(GPIO_TIMER_MODE);
    }
    else
    {
      setSleepMode(GPIO_MODE);
    }

    excuteDelay(60 * 10, delayConfigWifi); // 10分钟后关闭蓝牙广播
  }
}

long second = 0;

void handClickCB(String i)
{
  long v = i.toInt();
  if (v >= 5 * 60)
  {
    setClickButton(false);
  }
}

void setClickButtonLight()
{
  setClickButton(true);
  addGlobalTimerCallBack("handleClick", handClickCB);
}

void handleClick1()
{
  setClickButtonLight();
  // Serial.println("Clicked1");
  if (isBeep())
  {
    closeBeep();
  }

  if (isDisablePump())
  { // 如果是禁用状态，先强制解禁，再禁用
    setDisablePump(false);
    togglePump();
    setDisablePump(true);
    return;
  }
  togglePump();
}

void handleClick2()
{
  if (!isHanddleClick)
  {

    isHanddleClick = true;
  }
  else
  {
    isHanddleClick = false;
    return;
  }

  Serial.println("Clicked2");
  if (isBeep())
  {
    closeBeep();
  }

  if (isDisablePump())
  { // 如果是禁用状态，先强制解禁，再禁用
    setDisablePump(false);
    togglePump();
    setDisablePump(true);
    return;
  }
  togglePump();
}

bool ischeckTicks = false;

static int tickFlag = 0;
static long tickStartTime;
static long tickEndTime;

long lastTickTime = 0;

void cb(String i)
{
  ESP.restart();
}

Ticker btnTicker;

#define A_SIZE 4
static int aa[A_SIZE];
static int index1;
bool isInterupt = false;
long lastTime;

void btnPinCheckCB()
{

  int t = digitalRead(0);
  int ii = index1 % A_SIZE;
  aa[ii] = t;
  index1++;

  int c = 0;
  for (size_t i = 0; i < A_SIZE; i++)
  {
    c++;
    if (aa[i] == 1)
    {
      break;
    }
  }

  // Serial.println(c);
  if (c >= A_SIZE)
  {
    if (millis() - lastTime < 100)
    {
      return;
    }
    lastTime = millis();
    Serial.print("按下");
    isInterupt = false;
    btnTicker.detach();
    togglePump();

    return;
  }

  c = 0;
  for (size_t i = 0; i < A_SIZE; i++)
  {
    c++;
    if (aa[i] == 0)
    {
      break;
    }
  }

  if (c == A_SIZE)
  {
    printStr("松开");
    isInterupt = false;
    btnTicker.detach();

    return;
  }
}

void IRAM_ATTR checkTicks1()
{

  if (!isInterupt)
  {
    // printStr("ccc");
    isInterupt = true;
    btnTicker.attach_ms(25, btnPinCheckCB);
  }

  // togglePump();
  //  j++;
  //  if(j%2==0){
  //    togglePump();

  // }
}

void IRAM_ATTR checkTicks()
{

  if (!isAppReady())
  {
    return;
  }
  // Serial.println(millis());
  // Serial.println(lastTickTime);
  if (lastTickTime == 0)
  {
    lastTickTime = millis();
    // togglePump();
    // handleClick1();
  }
  else
  {
    if (millis() - lastTickTime <= 1000)
    {
      lastTickTime = millis();
      return;
    }
  }
  Serial.println("c");
  if (tickFlag == 0)
  {
    tickFlag = 1;
    tickStartTime = millis();
    // Serial.print("tickStartTime:");
    // Serial.println(tickStartTime);
    return;
  }

  if (tickFlag == 1)
  {
    tickEndTime = millis();
    // Serial.print("tickEndTime:");
    // Serial.println(tickEndTime);
    // Serial.print("interval");
    //  Serial.println(tickEndTime - tickStartTime);
    if (tickEndTime - tickStartTime >= 2000)
    {
      // Serial.println("长按事件");
      // if(!isAdvertising()){
      //   setNeedStartAdvertising(true);
      //   beepTimes(1);
      // }else{
      //  // stopAdvertising();
      //   beep(true);
      //   excuteDelay(1,cb);

      // }
    }
    else
    {
      Serial.println("点击事件");

      //  togglePump();
      handleClick1();
    }
    tickFlag = 0;
    // printStr("interval",tickEndTime-tickStartTime);
  }
}

void handleLongClick()
{
  Serial.println("handleLongClick.,.klljkkh");
  long interval = millis() - longClickPressTime;
  Serial.println(interval);
  if (interval >= 5000 && interval < 15000)
  {
    setSleepMode(GPIO_MODE);
    beep(true);
    delay(2000);
    beep(false);
    startSleep(1);
  }
  if (interval >= 15000)
  { // 长按15秒，改变模式
    beepTimes(3);
    delay(3000);
    changeEnvMode();
  }
}

// Handler function for a single click:
void handleClick()
{
  // Serial.println("Clicked!");
  if (isBeep())
  {
    closeBeep();
  }

  if (isDisablePump())
  { // 如果是禁用状态，先强制解禁，再禁用
    setDisablePump(false);
    togglePump();
    setDisablePump(true);
    return;
  }
  togglePump();
}

void attachButtonClick()
{
  // attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), checkTicks1, FALLING);

  btn.attachClick(handleClick1);
  btn.attachLongPressStop(handleLongClick);
  btn.attachLongPressStart(handleLongClickStart);
  btn.setPressMs(2000);
}

void setupMain()
{
  
}
void setButtonPin(int pin)
{
  BUTTON_PIN = pin;
}

bool checkLowPowerBoot()
{
  float threshold = 0.35;
  float vcc = getVcc();
  if (vcc <= threshold)
  {
    int wakeTime = 60 * 20;
    if (vcc <= 0.15)
    {
      wakeTime = 60 * 60;
    }
    gpio_set_direction(GPIO_NUM_0, GPIO_MODE_INPUT);
    esp_deep_sleep_enable_gpio_wakeup(BIT(0), ESP_GPIO_WAKEUP_GPIO_LOW);
    esp_sleep_enable_timer_wakeup(wakeTime * uS_TO_S_FACTOR);
    String str1 = "sleep now,after " + String(wakeTime) + " will wake up! and you can press button to wakeup!";
    Serial.println(str1);
    Serial.println("GPIO_TIMER_MODE");
    esp_deep_sleep_start();
    return false;
  }

  return true;
}
int wakeTime = 0;
void restartDelay(String i)
{
  gpio_set_direction(GPIO_NUM_0, GPIO_MODE_INPUT);
  esp_deep_sleep_enable_gpio_wakeup(BIT(0), ESP_GPIO_WAKEUP_GPIO_LOW);
  esp_sleep_enable_timer_wakeup(wakeTime * uS_TO_S_FACTOR);
  String str1 = "sleep now,after  " + String(wakeTime) + "s will wake up! and you can press button to wakeup!";
  Serial.println(str1);
  Serial.println("GPIO_TIMER_MODE");
  esp_deep_sleep_start();
}

bool restartVal = false;
void checkLowPower()
{
  if (restartVal)
  {
    return;
  }
  float threshold = 0;
  float vcc = getVcc();
  if (isPump())
  {
    threshold = 0;
   // float pinValue = getVccPinValue();
     float  pinValue =   getSensorPinValue("vcc");
    // vcc = convertVcc(pinValue);
    if(pinValue==0){
      pinValue = getVccPinValue();
    }

    if (pinValue <= 2000)
    {
      setPumpContinue(false);
      delay(2500);
      addLowPowerNotice("");
      printStr("addLowPowerNotice");
      excuteDelay(15, "restartDelay", restartDelay);
      restartVal = true;
      return;
    }
  }
  else
  {
    threshold = 0.2;
  }
  // printStr("Vcccc", vcc);

  String timeStr;
  if (vcc <= threshold)
  {
    wakeTime = 60 * 30;
    if (vcc == 0)
    {
      wakeTime = 60 * 60;
    }
    setPumpContinue(false);
    delay(2500);
    addLowPowerNotice("");
    printStr("addLowPowerNotice");
    excuteDelay(15, "restartDelay", restartDelay);
    restartVal = true;
    return;
  }
  else
  {
    ReqNotice notice = getLatestReqNotice("设备电量低");
    if (notice.isEmpty())
    {
      return;
    }
    long time = notice.getEpoch();
    long curTime = getRtcTime().getEpoch();
    if (curTime - time >= 60 * 60 * 24)
    {
      removePreference("设备电量低");
    }
  }
}

void loopMain()
{
 
  loopBtn();
  loopBle();

  // delay(1000);
  // printStr("j", j);
  //  if(isAdvertising()){
  //    blink("r",20*60);
  //  }
  // excuteTimerAction();

  if (isNeedSendActive())
  {
    requestActive(onActivePostBack, onActiveError);
    setNeedSendActive(false);
  }

  if (isNeedConnectWiFi()) // 标记是否要连接WiFi
  {
    int result = setUpWiFi();
    if (result == 0)
    {
      setWiFiConnected(true);
      Serial.println("连接成功");
      sendNotify("config-wifi-ok");
    }
    else
    {
      setWiFiConnected(false);
      String s = "config-wifi-error:";
      s.concat(result);
      Serial.println("连接失败");
      sendNotify(s);
    }
    setNeedConnectWiFi(false);
  }

  // if (isConnectWiFi)
  // {
  //   // loopMQTT();
  // }
}

bool isBootByWakeup(){
  if(getWakeupReason() == ESP_SLEEP_WAKEUP_GPIO||getWakeupReason() == ESP_SLEEP_WAKEUP_TIMER){
    return true;
  }
  return false;
}

void resetTriggle(String i)
{
  TimerAction *timerAction = getGlobalTimerAction();
  if (timerAction == nullptr)
  {
    return;
  }
  int dayOfWeek = getRtcTime().getDayofWeek();
  for (size_t i = 0; i < 7; i++)
  {
    if (i == dayOfWeek)
    {
      DayItem dayItem = timerAction->weekItems[i];
      for (size_t j = 0; j < dayItem.actionCount; j++)
      {
        TimerActionA *a = dayItem.actions[j];
        if (a != nullptr)
        {
          a->setTriggle(false);
        }
      }
    }
  }
}

static void processWeekTimerAction()
{
  TimerAction *timerAction = getGlobalTimerAction();
  if (timerAction == nullptr)
  {
    return;
  }

  long epoch = getRtcTime().getEpoch();
  int dayOfWeek = getRtcTime().getDayofWeek() - 1;

  // 处理间隔定时任务(7个ITEM)
  for (size_t i = 0; i < 7; i++)
  {
    if (i == dayOfWeek)
    {
      DayItem dayItem = timerAction->weekItems[i];
      for (size_t j = 0; j < dayItem.actionCount; j++)
      {
        TimerActionA *a = dayItem.actions[j];
        if (a != nullptr)
        {
          // long interval = epoch - a->getActionTime();

          String actionTimeStr = a->getActionTime();

          int hour = getRtcTime().getHour();
          int minite = getRtcTime().getMinute();
          int second = getRtcTime().getSecond();

          String ap = getRtcTime().getAmPm();
          if (ap.equals("PM"))
          {
            hour += 12;
          }
          int nowSecond = hour * 3600 + minite * 60 + second;
          String hstr = actionTimeStr.substring(0, actionTimeStr.indexOf(":"));
          String mstr = actionTimeStr.substring(actionTimeStr.indexOf(":") + 1, actionTimeStr.length());
      
          int actionTimeSecond = hstr.toInt() * 3600 + mstr.toInt() * 60;
          long interval = nowSecond - actionTimeSecond;
         // printStr("interval", interval);
          // printStr("getTimerWakeup", getTimerWakeup());
          if (getGlobalLocalConfig()->getTypeConfig()->getRunMode() == 1)
          { // 性能模式
            if (interval == 0)
            {
              Serial.println("周期定时触发");
              FuncCallBack1 cb = getGlobalFuncCallBack("weekAction");
              if (cb != nullptr)
              {
                cb(a);
              }
            }
          }
          else
          {//休眠模式
            if (interval >= 0 && interval <= (getTimerWakeup() + 60) && (!a->isTriggle()))
            {
              a->setTriggle(true);
              Serial.println("周期定时触发");
              FuncCallBack1 cb = getGlobalFuncCallBack("weekAction");
              if (cb != nullptr)
              {
                cb(a);
              }
            }
          }
        }
      }
    }
  }
}

static void processIntervalTimerAction()
{
  TimerAction *timerAction = getGlobalTimerAction();
  if (timerAction == nullptr)
  {
    return;
  }
  // 处理间隔定时任务
  for (size_t i = 0; i < timerAction->intervalActionCount; i++)
  {
    TimerActionB *b = timerAction->intervalTimerAction[i];
    if (b != nullptr)
    {

      if (gloablInterValAction[i].time == 0)
      {

        gloablInterValAction[i].time = getRtcTime().getEpoch();
      }
      else
      {
        long interval = computeIntervalCurrent(gloablInterValAction[i].time);
        if (interval >= b->getIntervalTime() && b->on)
        {
          Serial.println("间隔定时触发");
          // beepTimes(2);测试注释掉
          gloablInterValAction[i].time = getRtcTime().getEpoch();
          FuncCallBack1 cb = getGlobalFuncCallBack("intervalAction");
          if (cb != nullptr)
          {
            cb(b);
          }
        }
      }
    }
  }
}

static void processSingleTimerActionSleepMode()
{
  TimerAction *timerAction = getGlobalTimerAction();

  long epoch = getRtcTime().getEpoch();
  // 处理单次定时任务
  for (size_t i = 0; i < timerAction->singleActionCount; i++)
  {
    TimerActionA *a = timerAction->singleTimerAction[i];
    if (a != nullptr)
    {
      long interval = epoch - a->getActionTimeTimeStamp();
      if (interval >= 0 && interval <= getTimerWakeup() + 10 && (!a->isTriggle()))
      {
        a->setTriggle(true);
        Serial.println("省电单次定时触发");
        FuncCallBack1 cb = getGlobalFuncCallBack("singleAction");
        if (cb != nullptr)
        {
          cb(a);
        }
      }
    }
  }
}

static void processSingleTimerActionRealTimeMode()
{
  // printStr("processSingleTimerActionRealTimeMode", 0);
  TimerAction *timerAction = getGlobalTimerAction();
  if (timerAction == nullptr)
  {
    printStr("timerAction == nullptr", 0);
    return;
  }
  long epoch = getRtcTime().getEpoch();

  if (timerAction->singleActionCount != 0)
  {
    // printStr("timerAction->singleActionCount", timerAction->singleActionCount);
  }

  // 处理单次定时任务
  for (size_t i = 0; i < timerAction->singleActionCount; i++)
  {
    TimerActionA *a = timerAction->singleTimerAction[i];
    if (a != nullptr)
    {
      if (isStringEmpty(a->actionTime))
      {
        continue;
      }
      long actionTime = a->getActionTimeTimeStamp();
      long interval = epoch - actionTime;
      // printStr("interval",interval);

      if (interval >= 0 && interval <= 30 && (!a->isTriggle()))
      {
        Serial.println("性能模式单次定时触发");

        beepTimes(a->getDuration());
        a->setTriggle(true);

        FuncCallBack1 cb = getGlobalFuncCallBack("singleAction");
        if (cb != nullptr)
        {
          cb(a);
        }
      }
    }
    else
    {
    }
  }
}

void excuteTimerAction()
{
  TimerAction *timerAction = getGlobalTimerAction();
  if (timerAction == nullptr)
  {
    return;
  }
  processIntervalTimerAction();
  processWeekTimerAction();

  if (getAppMode() == APP_MODE_HIGH)
  {
    // printStr("processSingleTimerActionRealTimeMode");
    processSingleTimerActionRealTimeMode(); // 这里有问题，运行串口打印乱码，待解决
  }
  else if (getAppMode() == APP_MODE_SAVE)
  {
    // printStr("processSingleTimerActionSleepMode");
    processSingleTimerActionSleepMode();
  }
}
